﻿<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*" %>
<xn:title text="校内typeahead演示" />

<br>
<br>
<h2>
XNJS typeahead演示
</h2>
XNJS文档见<a href="http://dev.xiaonei.com/wiki/XNJS">XNJS</a>

<hr>
<br>
<h4>
typeahead演示
</h4>
<p>
下面的例子显示了 事件处理模型、Ajax、CSS样式等内容。
</p>
<br>
<br>
<br>

<style type="text/css">
.suggest_placeholder {
     color: #777; 
}

.suggest_found { 
    background: #e1e9f6; 
} 

.suggest_pretext { 
    color: #aaa; 
} 

.suggest_list { 
    background: transparent;
    border: 1px solid #bdc7d8; 
    border-top: none; 
    font-size: 11px; 
    margin-top: -1px; 
    overflow: hidden; 
    position: absolute; 
    text-align: left; 
    z-index: 102; 
} 

.suggest_list .suggest_suggestion { 
    background: #fff; 
    border-top: 1px solid #ddd; 
    color: #000; 
    cursor: pointer; 
    padding: 3px; 
    opacity: 0.94; 
    width: 100%; 
} 

.suggest_list .suggest_suggestion em { 
    background: #d8dfea; 
    color: black; 
    font-style: normal; 
    font-weight: bold; 
} 

.suggest_list .suggest_suggestion small { 
    color: #808080; 
    padding-left: 5px; 
} 

.suggest_list .suggest_selected { 
    background: #3b5998; 
    color: #fff; 
    opacity: 1; 
} 

.suggest_list .suggest_selected em { 
    background: #5670a6; 
    color: #fff; 
} 
</style>


<script type="text/javascript">
<!--
var options = {
    preMsgTxt: "type for suggestions", // text to display when nothing has been typed 
    menuOpacity: 94, // opacity of the menu 
    ajaxUrl: "http://www.leo.com/xnmlshell/demo/ajax_handler/typeahead.jsp", // url to your data source 
    focus: true, // whether or not to auto-focus the textbox upon creation 
    onEnter: function(event) {
        // handler for hitting the 'enter' key 
    },
    delayTime: 700, // amount of idle time after a keypress before making the ajax call
    clearOnEnter: false // whether or not to clear the text after they hit enter
}; 

function ajaxSuggest(obj, options) { 
    this.obj = obj; 
    
    // Setup the events we're listening to 
    this.obj.addEventListener('focus', this.onfocus); 
    this.obj.addEventListener('blur', this.onblur);
    this.obj.addEventListener('keyup', this.onkeyup);
    this.obj.addEventListener('keydown', this.onkeydown);
    this.obj.addEventListener('keypress', this.onkeypress); 
    
    // Create the dropdown list that contains our suggestions 
    this.list = document.createElement('div'); 
    this.list.setClassName('suggest_list');
    this.list.setStyle({width: this.obj.getOffsetWidth()-2+'px', display: 'none'}); 
    this.obj.getParentNode().appendChild(this.list); 
    
    // Various flags 
    this.focused = true; 
    this.options = options == null ? {} : options; 
    this.selectedindex = -1; 
    this.delayTime = options.delayTime == null ? 700 : options.delayTime; 
    this.preMsgTxt = options.preMsgTxt == null ? "type for suggestions" : options.preMsgTxt; 
    this.normOpac = options.menuOpacity == null ? 94 : options.menuOpacity; 
    this.curOpac = this.normOpac; 
    this.cache = {}; 
    this.obj.setStyle({margin: "0px"}); 
    if(!options.focus) { 
        this.preMsg = true; 
        this.obj.setValue(this.preMsgTxt); 
        this.obj.addClassName("suggest_pretext"); 
    } 
    else { 
        this.obj.focus(); 
        this.preMsg = false; 
        this.update_results(); 
        this.show(); 
    } 
}; 

var suggestr = null;

// Show suggestions when the user focuses the text field 
ajaxSuggest.prototype.onfocus = function(event) { 
    if (suggestr) {
        if (suggestr.preMsg) { 
            suggestr.obj.setValue(""); 
            suggestr.obj.removeClassName("suggest_pretext"); 
            suggestr.preMsg = false; 
        } 
        suggestr.focused = true; 
        suggestr.update_results(); 
        suggestr.obj.removeClassName('suggest_found'); 
        suggestr.show(); 
    }
}; 

// ...and hide it when they leave the text field 
ajaxSuggest.prototype.onblur = function() { 
    if (suggestr) {
        if(suggestr.obj.getValue() == "") { 
            suggestr.preMsg = true; 
            suggestr.obj.setValue(suggestr.preMsgTxt); 
            suggestr.obj.addClassName("suggest_pretext"); 
        } 
        
        suggestr.focused = false; 
        suggestr.hide(); 
    } 
}; 

// Every keypress updates the suggestions 
ajaxSuggest.prototype.onkeyup = function(event) {
    if (suggestr) {
        switch (event.keyCode) { 
            case 27: // escape 
                suggestr.hide(); 
                suggestr.obj.removeClassName('suggest_found'); 
                break; 
            case 13: // enter 
                if(suggestr.options!=null && suggestr.options.onEnter!=null) { 
                    suggestr.hide(); 
                    suggestr.options.onEnter(event); 
                    if(suggestr.options.clearOnEnter == true) { 
                        suggestr.obj.setValue(''); 
                        suggestr.hide(); 
                        suggestr.obj.removeClassName('suggest_found'); 
                    } 
                } 
                break; 
            case 0: 
            case 37: // left 
            case 9: // tab 
            case 38: // up 
            case 39: // right 
            case 40: // down 
                break; 
            default: 
                suggestr.selectedindex = -1; 
                suggestr.update_results(); 
                suggestr.show(); 
                suggestr.obj.removeClassName('suggest_found'); 
                break; 
        } 
    } 
}; 

// We want interactive stuff to happen on keydown to make it feel snappy 
ajaxSuggest.prototype.onkeydown = function(event) { 
    if (suggestr) {
        switch (event.keyCode) { 
            case 9: // tab 
            case 13: // enter 
                if (suggestr.results[suggestr.selectedindex]) { 
                    suggestr.obj.addClassName('suggest_found');
                    suggestr.obj.setValue(suggestr.results[suggestr.selectedindex]); 
                    suggestr.hide(); 
                    event.preventDefault(); 
                } 
                break; 
            case 38: // up 
                suggestr.select_index(suggestr.selectedindex - 1); 
                event.preventDefault(); 
                break; 
            case 40: // down 
                suggestr.select_index(suggestr.selectedindex + 1); 
                event.preventDefault(); 
                break; 
        } 
    } 
}; 

// Override these events so they don't actually do anything 
ajaxSuggest.prototype.onkeypress = function(event) { 
    switch (event.keyCode) { 
        case 13: // return 
        case 9: // tab 
        case 38: // up 
        case 40: // down 
            event.preventDefault(); 
            break; 
    } 
}; 

// Select a given index 
ajaxSuggest.prototype.select_index = function(index) { 
    var children = this.list.getChildNodes(); 
    if(children != null && children.length > 0) { 
        if(index<0) index = children.length - 1; 
        if(index >= children.length) 
            index = 0; 
        if(this.selectedindex >=0 && this.selectedindex < children.length ) 
            children[this.selectedindex].removeClassName('suggest_selected'); 
        children[(this.selectedindex=index)].addClassName('suggest_selected'); 
    } 
}; 

onajaxdone = function(data) { 
    // save to the cache 
    var suggestr = this.suggestr;
    if (suggestr) {
        suggestr.cache[data.fortext].results = data.results; 
        suggestr.cache[data.fortext].curRequest = null; 
        // if its valid, update the UI 
        if(suggestr.get_norm_typed() == data.fortext) { 
            suggestr.draw_results(data.results, data.fortext); 
            suggestr.results = data.results; 
        } 
    } 
}; 

ajaxSuggest.prototype.get_norm_typed = function() { 
    return this.obj.getValue().toLowerCase(); 
}; 

ajaxSuggest.prototype.getValue = function() { 
    return (this.preMsg?"":this.obj.getValue()); 
}; 

ajaxSuggest.prototype.draw_results = function(results, typed) { 
    this.list.setTextValue(''); 
    if(results == null) return; 
    var suggestr = this;
    for( var i = 0; i < results.length; i++ ) { 
        var item = document.createElement('div');
        item.setClassName('suggest_suggestion'); 
        item.index = i;
        item.addEventListener('mouseover', function(event) { 
                var target = event.target;
                if (typeof target.index != 'undefined') {
                    suggestr.select_index(target.index);
                } 
            }); 
        item.addEventListener('mousedown', function(event) { 
                suggestr.obj.addClassName('suggest_found');
                suggestr.obj.setValue(suggestr.results[suggestr.selectedindex]); 
                suggestr.hide(); 
            }); 
        var begins = results[i].toLowerCase().indexOf(typed); 
        if (begins == -1) { 
            var span_item = document.createElement('span');
            span_item.setTextValue(results[i]); 
            item.appendChild(span_item); 
        } 
        else { 
            if (begins > 0) { 
                var span_item2 = document.createElement('span');
                span_item2.setTextValue(results[i].substring(0, begins));
                item.appendChild(span_item2); 
            } 
            var em_item = document.createElement('em');
            em_item.setTextValue(results[i].substring(begins, begins + typed.length)); 
            item.appendChild(em_item); 
            var span_item = document.createElement('span');
            span_item.setTextValue(results[i].substring(begins + typed.length)); 
            item.appendChild(span_item); 
        } 
        this.list.appendChild(item); 
    } 
}; 

ajaxSuggest.prototype.send_ajrequest = function(val) { 
    // ajax query 
    var request = new Ajax(Ajax.JSON); 
    request.suggestr = this;
    request.requireLogin = false; 
    request.responseType = Ajax.JSON; 
    request.onerror = function() {}; 
    request.ondone = onajaxdone; 
    this.cache[val] = {curRequest: request}; 
    this.cache[val].curRequest.post(this.options.ajaxUrl, {suggest_typed: val}); 
}; 

// This is called every keypress to update the suggestions 
ajaxSuggest.prototype.update_results = function() { 
    // Search the list of potential results and find ones that match what we have so far 
    var val = this.get_norm_typed(); 
    if(this.cache[val] != null) { 
        // pull from el cache 
        this.draw_results(this.cache[val].results,val); 
        this.results = this.cache[val].results; 
    } 
    else if(this.cache[val] == null || this.cache[val].curRequest == null){ 
        if(this.requestTimer != null) 
            clearTimeout(this.requestTimer); 
        var suggestr = this;
        this.requestTimer = setTimeout( function() { suggestr.send_ajrequest(val); suggestr.requestTimer = null; }, this.delayTime); 
    } 
}; 

ajaxSuggest.prototype.show = function() { 
    this.list.setStyle('display', 'block'); 
}; 

ajaxSuggest.prototype.hide = function() { 
    this.selectedindex = -1; this.list.setStyle('display', 'none'); 
}; 
//-->
</script>

<div>
  <input id="typeahead_text" autocomplete="off" maxlength="20" type="text"/>
</div>
<script type="text/javascript">
<!--
suggestr = new ajaxSuggest(document.getElementById('typeahead_text'), options);
//-->
</script>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>